package com.liz.lizrpccore.lizspring.postprocessor;

import com.liz.lizrpccore.annotations.ProviderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author liangGongWei
 * @description
 * @create 2022-04-11 17:34
 **/

public class ProviderServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistryPostProcessor {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    private String packagesToScan;

    public String getPackagesToScan() {
        return packagesToScan;
    }

    public void setPackagesToScan(String packagesToScan) {
        this.packagesToScan = packagesToScan;
    }

    public ProviderServiceAnnotationBeanPostProcessor(String packagesToScan) {
        this.packagesToScan = packagesToScan;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        registerServiceBeans(packagesToScan, registry);
    }



    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }




    /**
    * ------------------------------------------------------私有方法------------------------------------------------------
    */


    private void registerServiceBeans(String packagesToScan, BeanDefinitionRegistry registry) {
        List<String> classNameList = new ArrayList<>();
        this.doScanPackage(packagesToScan,classNameList);
        List<String> filterList = new ArrayList<>();
        this.getAnnotationProviderServiceClass(classNameList,filterList);
        for (String className : filterList) {
            try {
                // 注册 bean
                Class<?> clazz = Class.forName(className);
                Class<?>[] interfaces = clazz.getInterfaces();
                String key = className;
                if (interfaces.length > 0){
                    key = interfaces[0].getName();
                }
                // 通过BeanDefinitionBuilder创建bean定义
                BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
                registry.registerBeanDefinition(key, beanDefinitionBuilder.getRawBeanDefinition());
            }catch (Exception e){
                logger.warn("注入bean失败，className:{}", className);
            }

        }

    }

    private void doScanPackage(String basePackages,List<String> classNameList) {
        String scanPath = basePackages.replaceAll("\\.", "/");
        //获取到当前包所在磁盘的全路径
        URL url = this.getClass().getClassLoader().getResource(scanPath);
        assert url != null;
        File files = new File(url.getFile());
        for (File file : files.listFiles()) {
            if (file.isDirectory()) {
                doScanPackage(basePackages + "." + file.getName(),classNameList);
            } else {
                classNameList.add(basePackages + "." + file.getName().replace(".class", ""));
            }
        }
    }
    private void getAnnotationProviderServiceClass(List<String> classNameList, List<String> filterList) {
        if (CollectionUtils.isEmpty(classNameList)) {
            return;
        }
        Iterator<String> iterator = classNameList.iterator();
        while (iterator.hasNext()) {
            try {
                String className = iterator.next();
                Class clazz = Class.forName(className);
                if (!clazz.isAnnotationPresent(ProviderService.class)) {
                    iterator.remove();
                    continue;
                }
                String name = className;
//                Class[] interfaces = clazz.getInterfaces();
//                if (interfaces.length > 0) {
//                    Class anInterface = interfaces[0];
//                    name = anInterface.getName();
//                }
                // 这里可以过滤掉Object类的方法，但是没有必要，先不搞
                // List<Method> methods = Arrays.asList(clazz.getMethods()).stream().filter(item -> !Object.class.equals(item.getDeclaringClass()))
                List<Method> methods = Arrays.asList(clazz.getMethods());
                List<String> collect = methods.stream().map(Method::getName).collect(Collectors.toList());
                filterList.add(name);
            } catch (Exception e) {
                logger.warn("扫描class异常：{}", iterator.next());
            }
        }
    }

}
